package com.clf.springBoot.modules.account.service.impl;

import com.clf.springBoot.modules.account.dao.UserDao;
import com.clf.springBoot.modules.account.dao.UserRoleDao;
import com.clf.springBoot.modules.account.entity.User;
import com.clf.springBoot.modules.account.entity.UserRole;
import com.clf.springBoot.modules.account.service.UserService;
import com.clf.springBoot.modules.common.vo.Result;
import com.clf.springBoot.modules.common.vo.Search;
import com.clf.springBoot.untils.MD5Util;
import com.clf.springBoot.untils.RedisUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Optional;

/**
 * @Author: chenglongfei
 * @date: 2022/7/7
 * @Description UserServiceImpl
 */
@Service
public class UserServiceImpl implements UserService {

    public final static Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);
    @Autowired
    private UserDao userDao;
    @Autowired
    private UserRoleDao userRoleDao;
    @Autowired
    private RedisUtils redisUtils;

    @Override
    @Transactional
    public Result<User> login(User user) {
//		User temp = userDao.getUserByUserNameAndPassword(user.getUserName(), MD5Util.getMD5(user.getPassword()));
//		if (temp == null) {
//			return new Result<>(Result.ResultStatus.FAILED.code, "用户名或密码错误。");
//		}
//		return new Result<>(Result.ResultStatus.SUCCESS.code, "Success.", temp);

        /**
         * 检查是否连续错误超过最大错误次数 3；
         * 是否在 30 秒之内
         * 如果满足上面两个条件，直接返回 result
         */
        // 最大错误次数
        int maxError = 3;
        String errorKey = String.format("login_error_count_%s", user.getUserName());
        // 错误次数
        int errorCount = redisUtils.get(errorKey)  == null ? 0 : (Integer) redisUtils.get(errorKey);
        if (errorCount >= maxError) {
            return new Result<>(Result.ResultStatus.FAILED.code,
                    String.format("用户连续错误登录三次，锁定账户 30 秒。"));
        }

        Subject subject = SecurityUtils.getSubject();
        // 登录令牌
        UsernamePasswordToken token =
                new UsernamePasswordToken(user.getUserName(), MD5Util.getMD5(user.getPassword()));

        User temp = null;
        try {
            subject.login(token);
            subject.checkRoles();

            temp = (User) subject.getPrincipal();
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.debug(e.getMessage());
            /**
             *  当输入错误时候，错误的次数累加 1
             *  判断错误次数是否超过最大值
             *  如果没超过，提示错误几次，还可以继续输入
             *  如果超过，设置 30 秒过期时间，并提示锁定账户 30 秒
             */
            redisUtils.increment(errorKey, 1);
            errorCount = redisUtils.get(errorKey)  == null ? 0 : (Integer) redisUtils.get(errorKey);
            if (errorCount >= maxError) {
                redisUtils.expire(errorKey, 30);
                return new Result<>(Result.ResultStatus.FAILED.code,
                        String.format("用户连续登录错误 %d 次，锁住账户 30 秒。", errorCount));
            } else  {
                return new Result<>(Result.ResultStatus.FAILED.code,
                        String.format("用户连续登录错误 %d 次，还剩 %d 次机会。", errorCount, (maxError - errorCount)));
            }
        }

        return new Result<>(Result.ResultStatus.SUCCESS.code, "Success.", temp);
    }

    @Override
    @Transactional
    public Result<User> insertUser(User user) {
        User temp = userDao.getUserByUserName(user.getUserName());
        if (temp != null) {
            return new Result<>(Result.ResultStatus.FAILED.code, "用户名重复");
        }

        user.setCreateDate(LocalDateTime.now());
        user.setPassword(MD5Util.getMD5(user.getPassword()));
        userDao.insertUser(user);
        if (user.getRoles() != null && user.getRoles().size() > 0) {
            user.getRoles().stream().forEach(item -> {
                userRoleDao.insertUserRole(new UserRole(user.getId(), item.getId()));
            });
        }

        return new Result<>(Result.ResultStatus.SUCCESS.code, "Insert success.", user);
    }

    @Override
    @Transactional
    public Result<User> updateUser(User user) {
        User temp = userDao.getUserByUserName(user.getUserName());
        if (temp != null && temp.getId() != user.getId()) {
            return new Result<>(Result.ResultStatus.FAILED.code, "用户名重复");
        }

        userDao.updateUser(user);
        userRoleDao.deleteUserRolesByUserId(user.getId());
        if (user.getRoles() != null && user.getRoles().size() > 0) {
            user.getRoles().stream().forEach(item -> {
                userRoleDao.insertUserRole(new UserRole(user.getId(), item.getId()));
            });
        }

        return new Result<>(Result.ResultStatus.SUCCESS.code, "Update success.", user);
    }

    @Override
    @Transactional
    public Result<Object> deleteUserById(int id) {
        userDao.deleteUserById(id);
        return new Result<>(Result.ResultStatus.SUCCESS.code, "Delete success.");
    }

    @Override
    public User getUserById(int id) {
        return userDao.getUserById(id);
    }

    @Override
    public User getUserByUserName(String userName) {
        return userDao.getUserByUserName(userName);
    }

    @Override
    public PageInfo<User> getUsersBySearch(Search search) {
        search.init();
        PageHelper.startPage(search.getCurrentPage(), search.getPageSize());
        return new PageInfo<>(Optional
                .ofNullable(userDao.getUsersBySearch(search))
                .orElse(Collections.emptyList()));
    }

    @Override
    public void logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
    }
}

//
//    @Override
//    @Transactional
//    public Result<User> insertUser1(User user) {
//        User user1=userDao.getUserByUserNameAndPassword(user.getUserName(),user.getPassword())
//
//        ;
//        if (user1 != null) {
//            return new Result<>(Result.ResultStatus.FAILED.code, "用户名已存在。");
//        }
//        user.setCreateDate(LocalDateTime.now());
//        user.setPassword(MD5Util.getMD5(user.getPassword()));
//        userDao.insertUser1(user);
//        return new Result<>(Result.ResultStatus.SUCCESS.code, "Success");
//    }
//
//
//}

